using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using Google.GData.Client;
using Google.GData.Extensions.MediaRss;
using Google.GData.YouTube;

namespace ScottLane.VideoInbox.Sources
{
    /// <summary>
    /// A video source that provides access to a YouTube user's video subscriptions, uploads,
    /// playlists and favorites.
    /// </summary>
    public class YouTubeSource : VideoSource
    {
        private YouTubeService service;
        private List<Video> videos;
        private List<Playlist> playlists;

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the YouTubeSource class.
        /// </summary>
        public YouTubeSource()
        {
            _checkUploadedVideos = true;
            _checkFavorites = true;
            _subscriptions = true;
            _checkPlaylists = true;
            _useHighQuality = true;
            _subscriptionLimit = 50;

            // todo - somehow hide this password
            service = new YouTubeService("Video Inbox", "client", "developerKey");
        }

        #endregion

        #region Properties

        private string _userName;

        /// <summary>
        /// Gets or sets the YouTube user name.
        /// </summary>
        public string UserName
        {
            get { return _userName; }
            set { _userName = value; }
        }

        private bool _checkFavorites;

        /// <summary>
        /// Gets or sets a value indicating whether to check the user's favorites.
        /// </summary>
        public bool CheckFavorites
        {
            get { return _checkFavorites; }
            set { _checkFavorites = value; }
        }

        private bool _subscriptions;

        /// <summary>
        /// Gets or sets a value indicating whether to check the user's subscriptions.
        /// </summary>
        public bool Subscriptions
        {
            get { return _subscriptions; }
            set { _subscriptions = value; }
        }

        private bool _checkUploadedVideos;

        /// <summary>
        /// Gets or sets a value indicating whether to check the user's uploaded videos.
        /// </summary>
        public bool CheckUploadedVideos
        {
            get { return _checkUploadedVideos; }
            set { _checkUploadedVideos = value; }
        }

        private bool _checkPlaylists;

        /// <summary>
        /// Gets or sets a value indicating whether to check the user's playlists.
        /// </summary>
        public bool CheckPlaylists
        {
            get { return _checkPlaylists; }
            set { _checkPlaylists = value; }
        }

        private bool _useHighQuality;

        /// <summary>
        /// Gets or sets a value indicating whether the high quality version of a video should be
        /// used if available.
        /// </summary>
        public bool UseHighQuality
        {
            get { return _useHighQuality; }
            set { _useHighQuality = value; }
        }

        private int _subscriptionLimit;

        /// <summary>
        /// Gets or sets the limit of videos that are downloaded per subscription.
        /// </summary>
        public int SubscriptionLimit
        {
            get { return _subscriptionLimit; }
            set { _subscriptionLimit = value; }
        }

        private int _playlistLimit;

        /// <summary>
        /// Gets or sets the limit of videos that are downloaded per playlist.
        /// </summary>
        /// <remarks>
        /// 0 = no limit.
        /// </remarks>
        public int PlaylistLimit
        {
            get { return _playlistLimit; }
            set { _playlistLimit = value; }
        }

        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override List<Video> GetNewVideos()
        {
            return GetNewVideos(_lastChecked);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override List<Video> GetNewVideos(DateTime startDate)
        {
            videos = new List<Video>();

            if (_checkUploadedVideos)
            {
                GetUploadedVideos(startDate);
            }

            if (_checkFavorites)
            {
                GetFavorites(startDate);
            }

            if (_subscriptions)
            {
                GetSubscriptions(startDate);
            }

            return videos;
        }

        /// <summary>
        /// Checks YouTube for user uploaded videos.
        /// </summary>
        private void GetUploadedVideos(DateTime startDate)
        {
            YouTubeQuery uploadsQuery = new YouTubeQuery("http://gdata.youtube.com/feeds/api/users/" + _userName + "/uploads");
            AddVideosFromQuery(uploadsQuery, startDate, Path.Combine(FolderPath, " Uploads"));
        }

        /// <summary>
        /// Checks YouTube for user favorite videos.
        /// </summary>
        private void GetFavorites(DateTime startDate)
        {
            YouTubeQuery favoritesQuery = new YouTubeQuery("http://gdata.youtube.com/feeds/api/users/" + _userName + "/favorites");
            AddVideosFromQuery(favoritesQuery, startDate, Path.Combine(FolderPath, " Favorites"));
        }

        /// <summary>
        /// Checks YouTube for user subscriptions.
        /// </summary>
        private void GetSubscriptions(DateTime startDate)
        {
            YouTubeQuery subscriptionsQuery = new YouTubeQuery("http://gdata.youtube.com/feeds/api/users/" + _userName + "/subscriptions");
            SubscriptionFeed subscriptions = service.GetSubscriptions(subscriptionsQuery);

            foreach (SubscriptionEntry subscription in subscriptions.Entries)
            {
                YouTubeQuery uploadsQuery = new YouTubeQuery("http://gdata.youtube.com/feeds/api/users/" + subscription.UserName + "/uploads");
                uploadsQuery.NumberToRetrieve = _subscriptionLimit;
                AddVideosFromQuery(uploadsQuery, startDate, null);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override List<Playlist> GetNewPlaylists()
        {
            return GetNewPlaylists(_lastChecked);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override List<Playlist> GetNewPlaylists(DateTime startDate)
        {
            playlists = new List<Playlist>();

            if (_checkPlaylists)
            {
                GetPlaylists(startDate);
            }

            return playlists;
        }

        /// <summary>
        /// Checks YouTube for user playlists.
        /// </summary>
        private void GetPlaylists(DateTime startDate)
        {
            //YouTubeQuery playlistQuery = new YouTubeQuery("http://gdata.youtube.com/feeds/api/users/" + _userName + "/playlists");
            //PlaylistsFeed playlists = service.GetPlaylists(playlistQuery);

            //foreach (PlaylistsEntry playlist in playlists.Entries)
            //{
            //    Playlist videoPlaylist = new Playlist();
            //    videoPlaylist.Title = playlist.Title.Text;
            //    videoPlaylist.FileName = Path.Combine(Path.Combine(Path.Combine(FolderPath, " Playlists"), videoPlaylist.Title), " Play All" + WvxFile.Extension);

            //    YouTubeQuery playlistVideoQuery = new YouTubeQuery(playlist.FeedLink.Href);
            //    playlistVideoQuery.NumberToRetrieve = _playlistLimit;
            //    YouTubeFeed playlistVideos = service.Query(playlistVideoQuery);

            //    foreach (YouTubeEntry playlistVideo in playlistVideos.Entries)
            //    {
            //        YouTubeVideo video = CreateVideoFromEntry(playlistVideo);
            //        video.ShortcutPath = Path.Combine(Path.Combine(FolderPath, " Playlists"), videoPlaylist.Title);
            //        videoPlaylist.Videos.Add(video);
            //        OnVideoFound(new VideoEventArgs(video)); // todo - this could be removed
            //    }

            //    OnPlaylistFound(new PlaylistEventArgs(videoPlaylist));
            //}
        }

        /// <summary>
        /// Adds the videos found in the YouTubeQuery to the video collection.
        /// </summary>
        /// <param name="query">The YouTubeQuery.</param>
        /// <param name="startDate"></param>
        /// <param name="shortcutPath">The path of a shortcut to create.</param>
        private void AddVideosFromQuery(YouTubeQuery query, DateTime startDate, string shortcutPath)
        {
            YouTubeFeed feed = service.Query(query);

            foreach (YouTubeEntry entry in feed.Entries)
            {
                YouTubeVideo video = YouTubeVideo.Create(entry);

                if (video.Created >= startDate)
                {
                    string extension = ".flv";

                    if (_useHighQuality && video.HighQualityAvailable)
                    {
                        video.SourceLocation = video.SourceLocationHighQuality;
                        extension = ".mp4";
                    }
                    else
                    {
                        video.SourceLocation = video.SourceLocationLowQuality;
                    }

                    string folder = Path.Combine(FolderPath, video.Author);
                    video.DownloadFileName = Path.Combine(folder, video.Title + extension);

                    if (shortcutPath != null)
                    {
                        video.Shortcuts.Add(new Shortcut(shortcutPath, video.Title, video.DownloadFileName));
                    }

                    videos.Add(video);
                }
            }
        }
    }
}
